package n13_reentrantlock;

import lombok.extern.slf4j.Slf4j;
import utils.Sleeper;

import java.util.Random;
import java.util.concurrent.locks.ReentrantLock;

/**
 * @author fu
 * @date 2021-12-29 17:39
 * 概要：
 * ------------------------------------------------
 * |                                              |
 * |                哲学家就餐问题                  |
 * |                                              |
 * |===============================================
 *
 * 吃饭时要用两根筷子吃，桌上共有 5 根筷子，每位哲学家左右手边各有一根筷子。
 * 如果筷子被身边的人拿着，自己就得等待
 */
public class T4_zhexuejia_jiucan {

    public static void main(String[] args) {

        Chopstick c1 = new Chopstick("1");
        Chopstick c2 = new Chopstick("2");
        Chopstick c3 = new Chopstick("3");
        Chopstick c4 = new Chopstick("4");
        Chopstick c5 = new Chopstick("5");
        new Philosopher("苏格拉底--",   c1, c2).start();
        new Philosopher("柏拉图---",     c2, c3).start();
        new Philosopher("亚里士多德",  c3, c4).start();
        new Philosopher("赫拉克利特",  c4, c5).start();
        new Philosopher("阿基米德--",    c5, c1).start();

    }

}

// 哲学家类          [--- 继承了 Thread类 ---]
@Slf4j(topic = "c.P")
class Philosopher extends Thread {
    Chopstick left;
    Chopstick right;
    public Philosopher(String name, Chopstick left, Chopstick right) {
        super(name);
        this.left = left;
        this.right = right;
    }

    @Override
    public void run() {

        while (true) {
            // 获得左手筷子
            if(left.tryLock()){
                try {
                    // 如果获取右手筷子 ===> eat ===> 释放        【---------- 如果没有获得右手筷子 就释放左手筷子 ----------】
                    if(right.tryLock()){
                        log.debug("+++ 获得 左右手筷子+++");
                        // 吃饭
                        try {
                            eat();
                        } finally {
                            right.unlock();
                        }
                    }

                } finally {

                    left.unlock();
                }
            }

//            synchronized (left) {
//                log.debug("--- 获得 左手筷子---");
//                // 获得右手筷子
//                synchronized (right) {
//                    log.debug("+++ 获得 右手筷子+++");
//                    // 吃饭
//                    eat();
//                }
//                // 放下右手筷子
//            }
//            // 放下左手筷子
        }
    }

    private void eat() {
        log.debug("eating...");
        Sleeper.sleep(1);
    }
}


// 筷子类
class Chopstick extends ReentrantLock {
    String name;
    public Chopstick(String name) {
        this.name = name;
    }
    @Override
    public String toString() {
        return "筷子{" + name + '}';
    }
}



